package com.lyr.test.custom;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AopUtils;

import java.lang.reflect.Method;

/**
 * 这里不直接在这里实现 MethodMatcher,ClassFilter 接口也行的
 */

public class MyDbMasterPointcut implements Pointcut, MethodMatcher, ClassFilter {
    /**
     * 这里是核心匹配过程，可能是个非常复杂的匹配过程
     * 这个只能匹配到方法级别，也就是只能判断这个方法是否被什么修饰之类的
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        /**
         * 可以在这里拿到原始方法，判断这个方法上是否标注了注解才可以
         * method 这个方法对象是接口上的，注意了，接口上没有任何的注解修饰，拿到死都拿不到
         * 所以可以通过这个 AopUtils 工具类获取到实习类上的 method 对象
         * 或者可以通过 targetClass 字节码文件获取到都可以，方法很多
         */
        Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
        if (specificMethod.isAnnotationPresent(DBMaster.class)) {
            System.out.println("匹配到了有 @DBMaster 修饰的方法,可以对其进行拦截操作:" + method.getName());
            return true;
        }
        return false;
    }


    /**
     * 这里是核心匹配过程，可能是个非常复杂的匹配过程
     * 这个不仅可以匹配方法，还可以匹配参数级别
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass, Object... args) {
        System.out.println("-------> 方法匹配成功了，然后开始参数级别的 matches() ...");
        // 先检验方法是否符合要求
        if (method.getName().equalsIgnoreCase("crateOrder")) {
            // 然后再检验参数是否符合要求
            String name = (String) args[0];
            if ("小明".equalsIgnoreCase(name)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isRuntime() {
        /**
         * 这里返回 true 参数级别的校验方法才会执行
         * 这里方法 false 下面就不会被执行，看源码就知道了
         */
        return true;
    }


    @Override
    public ClassFilter getClassFilter() {
        /**
         * 当前自己就是 ClassFilter 所以直接返回 this
         * 但是由于我们的 @DBMaster 注解是对方法起作用的，所以这里就没必要对类进行校验操作了
         * 或者没必要实现 ClassFilter 接口，直接在 getClassFilter() 方法上返回 ClassFilter.TRUE
         */
        return this;
        //return ClassFilter.TRUE;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }

    /**
     * 重写 ClassFilter 方法 对类的匹配
     * 但是由于我们的 @DBMaster 注解是对方法起作用的，所以这里就没必要对类进行校验操作了
     * 或者没必要实现 ClassFilter 接口，直接在 getClassFilter() 方法上返回 ClassFilter.TRUE
     */
    @Override
    public boolean matches(Class<?> clazz) {
        return true;
    }
}

